﻿#region Using

using System;
using System.Configuration;
using System.Web.Configuration;
using System.Web.WebPages;
using Microsoft.Ajax.Utilities;

#endregion

namespace WebApp
{
  /// <summary>
  ///     Provides access to the current application's configuration file.
  /// </summary>
  public static class Settings
  {
    /// <summary>
    ///     Specifies the default entry prefix value ("config").
    /// </summary>
    private const string Prefix = "config";

    /// <summary>
    ///     Retrieves the entry value for the following composed key: "config:Company" as a string.
    /// </summary>
    public static readonly string Company = GetValue<string>("Company");

    /// <summary>
    ///     Retrieves the entry value for the following composed key: "config:Project" as a string.
    /// </summary>
    public static readonly string Project = GetValue<string>("Project");

    /// <summary>
    ///     Retrieves the entry value for the following composed key: "config:EnableTiles" as a boolean.
    /// </summary>
    public static readonly bool EnableTiles = GetValue<bool>("EnableTiles");

    /// <summary>
    ///     Retrieves the entry value for the following composed key: "config:EnableLoader" as a boolean.
    /// </summary>
    public static readonly bool EnableLoader = GetValue<bool>("EnableLoader");

    /// <summary>
    ///     Retrieves the entry value for the following composed key: "config:CurrentTheme" as a string.
    /// </summary>
    public static readonly string CurrentTheme = GetValue<string>("CurrentTheme");

    /// <summary>
    ///     Gets the entry for the given key and prefix and retrieves its value as the specified type.
    ///     <para>If no prefix is specified the default prefix value ("config") will be used.</para>
    ///     <para>
    ///         <example>e.g. GetValue&lt;string&gt;("config", "SettingName")</example>
    ///     </para>
    ///     Would result in checking the configuration file for a key named: "config:SettingName"
    /// </summary>
    /// <typeparam name="T">The type of which the value will be converted into and returned.</typeparam>
    /// <param name="prefix">The prefix of the entry to locate.</param>
    /// <param name="key">The key of the entry to locate.</param>
    /// <returns>The value of the entry, or the default value, as the specified type.</returns>
    public static T GetValue<T>(string key, string prefix = Prefix)
    {
      var entry = string.Format("{0}:{1}", prefix, key);

      // Make sure the key represents a possible valid entry
      if (entry.IsNullOrWhiteSpace())
        return default(T);

      var value = ConfigurationManager.AppSettings[entry];

      // If the key is available but does not contain any value, return the default value of the specfied type
      if (value.IsNullOrWhiteSpace())
        return default(T);

      // In case the specified type is an enum, try to parse the entry as an enum value
      if (typeof(T).IsEnum)
        return (T)Enum.Parse(typeof(T), value, true);

      // In case the specified type is a bool and the entry value represents an integer
      if (typeof(T) == typeof(bool) && value.Is<int>())
        // We convert to value to an integer first before changing the entry value to the specified type
        return (T)Convert.ChangeType(value.As<int>(), typeof(T));

      // Change the entry value to the specified type
      return (T)Convert.ChangeType(value, typeof(T));
    }

    /// <summary>
    ///     To dynamical replace the appSettings "config:CurrentTheme"
    ///     Calling function such as Settings.SetValue<string>("config:CurrentTheme", "smart-style-0");
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">the key of the theme === config:CurrentTheme</param>
    /// <param name="value">the value of the theme === smart-style-{0}</param>
    /// <returns></returns>
    public static T SetValue<T>(string key, string value)
    {
      var config = WebConfigurationManager.OpenWebConfiguration("~");

      config.AppSettings.Settings[key].Value = value;
      config.Save(ConfigurationSaveMode.Modified);
      ConfigurationManager.RefreshSection("appSettings");

      return default(T);
    }

  }
}